/*
 * File: AndroidMusic
 * Created: 13-JUN-2011
 * Author: Colin Gall-McDaid
 * 
 * Description: Android implementation of the Music framework. 
 * Stores a MediaPlayer instance along with a boolean called isPrepared. The booelan
 * isPrepared helps keep track of the state of the MediaPlayer as it's
 * start/stop/pause methods can only be called when the MediaPlayer is prepared.
 */
package com.gallsoft.games.framework.impl;

import java.io.IOException;

import android.content.res.AssetFileDescriptor;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;

import com.gallsoft.games.framework.Music;

public class AndroidMusic implements Music, OnCompletionListener {

    private MediaPlayer mediaPlayer;
    private boolean isPrepared = false;

    /**
     * Constructor
     * 
     * @param assetDescriptor Android asset (resource) descriptor
     */
    public AndroidMusic(AssetFileDescriptor assetDescriptor) {
        mediaPlayer = new MediaPlayer();

        try {
            mediaPlayer.setDataSource(assetDescriptor.getFileDescriptor(), assetDescriptor.getStartOffset(), assetDescriptor.getLength());
            mediaPlayer.prepare();
            mediaPlayer.setOnCompletionListener(this);

            isPrepared = true;
        } catch (Exception e) {
            throw new RuntimeException("Couldn't load music");
        }
    }

    /**
     * Play the media file. Checks if MediaPlayer is already prepared and
     * prepares it if necessary. Needs to be synchronized as the isPrepared flag
     * might get set on a separate thread due to the implementation of
     * OnCompletionListener
     */
    public void play() {
        if (mediaPlayer.isPlaying())
            return;

        try {
            synchronized (this) {
                if (!isPrepared) {
                    mediaPlayer.prepare();
                    isPrepared = true;
                }
                mediaPlayer.start();
            }
        } catch (IllegalStateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Stop the MediaPlayer
     */
    public void stop() {
        mediaPlayer.stop();

        synchronized (this) {
            isPrepared = false;
        }
    }

    /**
     * Pause the MediaPlayer
     */
    public void pause() {
        mediaPlayer.pause();
    }

    /**
     * Set the looping state of the MediaPlayer
     * 
     * @param isLooping looping state
     */
    public void setLooping(boolean isLooping) {
        mediaPlayer.setLooping(isLooping);
    }

    /**
     * Set the MediaPlayer volume
     */
    public void setVolume(float volume) {
        mediaPlayer.setVolume(volume, volume);
    }

    /**
     * Check if MediaPlayer is playing
     */
    public boolean isPlaying() {
        return mediaPlayer.isPlaying();
    }

    /**
     * Check if MediaPlayer has stopped. Uses isPrepared flag as the MediaPlayer
     * will return false if paused
     */
    public boolean isStopped() {
        return !isPrepared;
    }

    /**
     * Check looping state of MediaPlayer
     */
    public boolean isLooping() {
        return mediaPlayer.isLooping();
    }

    /**
     * Dispose of a MediaPlayer. First checks if the MediaPlayer is still
     * playing, and if so, stops it.
     */
    public void dispose() {
        if (mediaPlayer.isPlaying())
            mediaPlayer.stop();

        mediaPlayer.release();
    }

    /**
     * Sets the isPrepared flag to false
     */
    public void onCompletion(MediaPlayer arg0) {
        synchronized (this) {
            isPrepared = false;
        }
    }

}
